\chapter{CRUD in Gantry}
\label{chap:fullcrud}

Gantry provides two schemes for automating database Create, Update, and
Delete\index{CRUD}
(CRUD).\footnote{Note that retrieval is handled in other ways, usually with
direct help from an Object-Relational Mapper, a.k.a. an ORM}  One scheme
is called AutoCRUD, since it can do everything
-- except make your form.  But, it does have various controls and hooks for
customization.  The other scheme does form validation and redirections, with
a lot of code from you.  It is called CRUD, to indicate the extra work
you must do to use it.  This chapter describes both schemes.

Since one of the schemes is called CRUD, when I want to refer to both of
them I will use the lowercase crud -- even though this is acronym abuse.

The two schemes do have one main feature in common, they both display a
form in which the user adds to or modifies values in the database.  The
first section, immediately below, describes these forms.  The later
sections describe each scheme's unique features.

\section{Forms\index{forms for crud schemes}}

Both crud schemes use Data::FormValidator\begin{footnote}You can implement your
own validation with the \verb+validator+ callback in CRUD.  See
subsection \ref{ssec:validate} near the end of this chapter for
details.\end{footnote}
for form validation and share
\texttt{form.tt} as their default form template.  Thus, their form methods
are very
similar.  While bigtop can make the form method for you, you might still
want to know what is in it or how to roll your own, hence this section.

Form routines are called during add and edit operations by the crud scheme.
They are called in slightly (but only slightly) different ways by CRUD and
AutoCRUD.  Here is the
difference:\index{CRUD!auto vs. custom forms}
during edit AutoCRUD passes the ORM row
object being edited to the form method, while CRUD always passes whatever
data you passed to its add or edit method.  You should put the row object
in there, but you can include anything else your method needs.  Other than
that, the methods are the same.

I will now begin assuming that you are using the Gantry standard
\texttt{form.tt}
to display the form.  If you have made your own replacement, you must
return the structure it expects from your form method.  Even so, the fields
array must be the same, otherwise form validation won't work.

Your form method must return a hash reference, which will be passed
directly to \texttt{form.tt}.\index{form.tt@texttt{form.tt}}
Further, its `fields' key will be passed to the
internal \verb+form_profile+ method.  It places certain expectations on
the members of the fields array, which are needed to use Data::FormValidator,
see below.

Table \ref{tab:formkeys} shows the top level keys in the hash you should return
(required keys are listed at the top for ease of reference).
Most of these are optional and are not particularly interesting.  A couple
need a few more words.  These are: \verb+fields+, \verb+change_log+,
and \verb+javascript+.  I'll take them in reverse order.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Key                & Value \\
\hline
\multicolumn{2}{l}{Required} \\
\hline
\verb+fields+      & An array of fields which appear on the form. \\
                   & See below.                                   \\
\verb+row+         & (for editing) The ORM object being edited.   \\
\hline
\multicolumn{2}{l}{Optional} \\
\hline
\verb+action+      & The URL which will process the page,       \\
                   & defaults to \verb+$self->uri$+.            \\
\verb+cellspacing+ & The cellspacing of the form's table,       \\
                   &                defaults to 0.              \\
\verb+change_log+  & An array of change log entries.            \\
                   &                See below.                  \\
\verb+javascript+  & Any Javascript your form needs.            \\
\verb+legend+      & The fieldset legend above the form.        \\
\verb+method+      & POST or GET, defaults to POST.             \\
\verb+name+        & The HTML DOM name of the form.             \\
\verb+width+       & The width of the form's table.  By default \\
                   & the width attribute is omitted.            \\
\end{tabular}
\end{center}
\caption{Form method return value hash keys.}
\label{tab:formkeys}
\end{table}

Some forms need to add
Javascript\index{Javascript!on crud forms}.
If yours does, use the \verb+javascript+
key.  Give it a value that is a correct and balanced script tag.  One
particularly useful way to get one of those is by calling a method that
makes them.  For instance, if you want rather old fashioned date popups,
you could use
Gantry::Plugins::Calendar,\index{calendar, Gantry popup plugin}
then call \verb+calendar_month_js+\index{calendar month
js@\verb+calendar_month_js+} on yourself
with the name of your form, something like this:

{\footnotesize
\begin{verbatim}
use Gantry::Plugins::Calendar;

#...
sub form {
    my ( $self, $row ) = @_;

    #...
    return {
        name => 'my_form',
        #...
        javascript => $self->calendar_month_js( 'my_form' ),
        #...
    }
}
\end{verbatim}
}

Then, if any of your fields have
\verb+date_select_text+\index{date select text@\verb+date_select_text+}
(see below), users
will be given a link to a popup calendar to populate their date fields for
them.

The \verb+change_log+\index{form.tt@\texttt{form.tt}!change
log}\index{change log on form.tt@\texttt{form.tt}}
key is quite specialized, so you may never need it.
But, if you want to show a little change log summary on the right side of
your add/edit form, include this key and fill its value with a reference
to an array of hashes, each of which has the keys in
Table \ref{tab:changelogkeys}.
Note that you must format the dates yourself, \texttt{form.tt}
will not do that.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Key                & Value \\
\hline
date               & date the change happened               \\
by                 & name of the person who made the change \\
message            & what happened                          \\
\end{tabular}
\end{center}
\caption{Change log keys for default form template.}
\label{tab:changelogkeys}
\end{table}

Finally, we come to the main point of interest: the \verb+fields+ key.
The value for this key is an array reference.  Each element of the array
is a hash reference.  There are two types of keys in each hash: those
that depend on the type of the field and those that don't.  The
type independent keys are shown in Table \ref{tab:formfieldskeys}.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Key & Value \\
\hline
\verb+default_value+ & The fields value if no other value can      \\
                     & be found.                                   \\
\verb+label+         & What the user sees to the left of the input \\
                     & field.                                      \\
\verb+name+          & The name of the database column for this    \\
                     & field, which is also the HTML name of its   \\
                     & input element.                              \\
\verb+raw_html+      & Copied directly to HTML output immediately  \\
                     & before the field's table row.               \\
\verb+type+          & One of: \verb+text+, \verb+textarea+, \verb+display+
                       \verb+select+, or \\
                     & \verb+select_multiple+.          \\
\verb+width+         & Width of the \verb+<+td\verb+>+ surrounding the \\
                     & input element.                                     \\
\end{tabular}
\end{center}
\caption{Hash keys for fields array for the default form.}
\label{tab:formfieldskeys}
\end{table}

A few words about defaults\index{form.tt@\texttt{form.tt}!defaults}
is in order.  The default value for a field
is chosen through a series of tests.  First, when the user clicks `Save,'
but Data::FormValidator does not like one or more of the fields,
default values will be whatever the user entered.  Second,
if the form has not yet been submitted, and a row is being edited, the
values in the database for that row are the defaults.  Third, if nothing
else has set a default, the
\verb+default_value+\index{default values@\verb+default_value+ on
texttt{form.tt}}
in the fields array is
used.  When all else fails the normal HTML form defaults apply.

The remaining keys depend on the type key, so I'll show you one table
for each type.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Key & Value\\
\hline
\verb+options+ & An array of hashes with value and label keys.\\
\end{tabular}
\end{center}
\caption{Additional required key for `select' fields.}
\label{tab:selectfieldkeys}
\end{table}

Fields of type \texttt{select} have the additional required key in Table
\ref{tab:selectfieldkeys}.  By calling
\verb+get_form_selections+\index{get form
selections@\verb+get_form_selections+} on your model,
you can often avoid coding the options for your select field.
That method returns a hash you can use like this:

{\footnotesize
\begin{verbatim}
    my $selections = $MY_MODEL->get_form_selections(
#            { schema => $self->get_schema }  # for DBIx::Class
    );

    #...
    return {
        #...
        fields => [
            {
                name    => other_table_id,
                label   => 'Other Table',
                type    => 'select',
                options => $selections->{other_table},
            },
            #...
        ],
    }
\end{verbatim}
}

If you are using
DBIx::Class,\index{DBIx::Class!and get form selections}
you need to pass your schema to \verb+get_form_selections+.  Use
Gantry::Plugins::DBIxClassConn,\index{DBIx::Class!Gantry plugin}
in your controller and call
\verb+get_schema+\index{get schema@\verb+get_schema+}
on your self object to get the schema.

The \verb+options+ key wants an array, so you could say the above manually
like this:
{\footnotesize
\begin{verbatim}
options => [
    { label => 'On-Site', value => 'onsite' },
    { label => 'Partial Telecommute', value => 'parttele' },
    { label => 'Telecommute', value => 'tele' },
],
\end{verbatim}
}
\noindent
which bigtop generated for the job ad example in Chapter\ref{chap:jobadsapp}.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Key & Value\\
\hline
\verb+selected+ & A code reference (see below). \\
\end{tabular}
\end{center}
\caption{Additional required key for `select multiple' fields.}
\label{tab:selectmultfieldkeys}
\end{table}

Fields of type \verb+select_multiple+ are very similar to regular
\verb+select+ fields.  They have one additional key, shown in Table
\ref{tab:selectmultfieldkeys}.
The \verb+selected+\index{selected@\verb+selected+, code ref for select
multiple}
code reference is called with one of the option
values and the form parameters hash (as a reference).  It must return
a true value if the passed in option is selected and false otherwise.
The easiest way to get a selected code references is ask for the one
exported by CRUD\index{CRUD!select multiple closure}
(it is only exported by request):

{\footnotesize
\begin{verbatim}
use Gantry::Plugins::CRUD qw( select_multiple_closure );

#...
sub your_form {

    # Fish the selected rows from database,
    # put them in %selected.
    my %selected;

    return {
        #...
        {
            name => 'choosemany',
            type => 'select_multiple',
            label => 'Choose all that apply.',
            options => \@options,
            selected => select_multiple_closure(
                'choosemany',   # needs to match name above
                \%selected,
            ),
    };
}
\end{verbatim}
}

This requires you to build \verb+@options+ and \verb+%selected+ ahead
of time.  The \verb+@options+ should be all the legal choices, while
\verb+%selected+ is a hash of items currently selected in the database.
The closure will use the database selections on initial page load and
previous form selections when the page fails to validate.

Fields of type \texttt{display} are only shown to the user.  They may not be
edited.  They have one additional optional key, shown in Table
\ref{tab:displayfieldkeys}.
Fields of type \texttt{textarea} have the additional optional keys in
Table \ref{tab:textareafieldkeys}.
Fields of type \texttt{text} have the additional optional keys in
Table \ref{tab:textfieldkeys}.
The size is called \verb+display_size+ to avoid a collision with a
Template Toolkit pseudo-method called size.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Key & Value\\
\hline
\verb+foreign+ & Table name this column points to. \\
\end{tabular}
\end{center}
\caption{Additional optional key for `display' fields.}
\label{tab:displayfieldkeys}
\end{table}

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Key & Value\\
\hline
\verb+rows+ & The HTML rows attribute for the textarea element. \\
\verb+cols+ & The HTML cols attribute for the textarea element. \\
\end{tabular}
\end{center}
\caption{Additional optional keys for `textarea' fields.}
\label{tab:textareafieldkeys}
\end{table}

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Key & Value\\
\hline
\verb+date_select_text+ & Indicates that the field is a date the user  \\
                        & may populate with a popup calendar           \\
                        & window.   The value is the text of the link  \\
                        & which pops up the calendar.                  \\
\verb+display_size+     & The HTML size attribute for the text         \\
                        & input element.                               \\
\end{tabular}
\end{center}
\caption{Additional optional keys for `text' fields.}
\label{tab:textfieldkeys}
\end{table}

You may include other keys in the fields hashes as well.  For instance,
bigtop pollutes the hash with extra information meant for use during
project generation.  But it could help you too, since the extra keys
are available to any caller of the form method.  One of those caller's
might be you.

\section{AutoCRUD\index{AutoCRUD}}

In most cases, AutoCRUD is all you need.  Yet, some prefer to take more
control even when they don't actually need to.  Feel free to use CRUD even
when AutoCRUD would do, the next section shows you how.  But, if you're as
lazy as I am, automation sounds good and this section is for you.

When bigtop makes your controllers for use with AutoCRUD, it assumes you
don't want to do any work.  This may give you the impression that you can't
control anything it does, let's disabuse you of that notion.
Before moving on to the really interesting parts, here are the things
that are easily controlled by implementing simple methods.

One of the easiest things to control is the template used to show the form.
By default that is \texttt{form.tt} which ships with Gantry.  To change it,
put a form template into your Template Toolkit root path and implement
a method\index{form name method} in your controller:

{\footnotesize
\begin{verbatim}
sub form_name { return 'my_form_name.tt'; }
\end{verbatim}
}

When you implement \verb+form_name+, omit that method from
your use statement for Gantry::Plugins::AutoCRUD.  Otherwise, you'll get
a redefinition warning, creating confusion over which method is in effect.

Another easily controlled item is the
text description\index{text
description@\verb+text_description+}\index{AutoCRUD!text
description@\verb+text_description+}
users see in browser
title bars and in the blank in `Delete \verb+____+?'  You must specify this
with a method like this:

{\footnotesize
\begin{verbatim}
sub text_descr { return 'item'; }
\end{verbatim}
}

The other controllable parts require a bit more work, so they have their
own subsections.

\subsection{Controlling Redirection}

At the bottom of any \texttt{form.tt} generated form is a pair of buttons: Save
and Cancel.  Cancel is always successful, pressing it takes the user
somewhere.  By default they return to the page from which they clicked
`Add,' `Edit,' or `Delete.'  Also by default, when Saving is successful,
they are delivered to the same place.  But you can override the
defaults, to gain complete programmatic control of the
redirection\index{AutoCRUD!redirection location}
location, which I will now begin abbreviating as the relocation.

There are two approaches to controlling relocations.  First, you can implement
a single method called
\verb+get_relocation+.\index{get relocation@\verb+get_relocation+}
It receives two parameters.
First is the action underway: 
\verb+add+, \verb+edit+, or \verb+delete+.  Second is the button
pressed: \verb+submit+ or \verb+cancel+.  From these, you decide where the
user should go and return any valid URL.  For example:

{\footnotesize
\begin{verbatim}
sub get_relocation {
    my ( $self, $update_type, $button_pressed ) = @_;

    return '/site_home';
}
\end{verbatim}
}

You'll probably want to do something more interesting than always sending
everyone to the same top level location.  As you work, keep in mind that
the Gantry site object (called \verb+$self+ above) is full of useful
information you can use to decide where the user should go.  For example, it
has \verb+location+ and \verb+uri+ methods and many others.  See
Chapter \ref{chap:site} or the docs for Gantry.pm and your engine
for a list of available methods, but note that various
plugins add to that list.

Implementing a single relocation method can become tedious when you need
to do a lot of testing to determine where the user should go.  So,
as an alternative, you may choose to implement
two methods\index{get cancel
loc@\verb+get_cancel_loc+}\index{get save loc@\verb+get_save_loc+}
instead: one
for cancellations and the other for successful submissions.
For consistency, these methods are called with exactly the same parameters
as \verb+get_relocation+, even though the pressed button is redudant for them.
Here are examples:

{\footnotesize
\begin{verbatim}
sub get_cancel_loc {
    my ( $self, $update_type, $button_pressed ) = @_;

    return '/home/sorry';
}
sub get_submit_loc {
    my ( $self, $update_type, $button_pressed ) = @_;

    return '/home/thanks';
}
\end{verbatim}
}

Note that \verb+get_relocation+ takes precedence.  If you have one, both
of the other relocation methods will be ignored.

\subsection{Data Cleanup Hooks and Hard Bail Outs}

After the user submits the form and it has been validated, but before
making any changes to the database AutoCRUD will call
hook\index{AutoCRUD!callback hooks}
methods, if
they are defined.  These are the prehooks, since they happen prior to
database changes.

For example, just before a successful row addition, AutoCRUD attempts
to call \verb+add_pre_action+.\index{add pre action@\verb+add_pre_action+}
If the method exists, it will be called
with a reference to the hash of form values (minus the submit key).
Perform any needed operations on that hash and return nothing.  This is
a good place to convert numbers to booleans, to add creation times,
etc.

Similarly, \verb+edit_pre_action+\index{edit pre action@\verb+edit_pre_action+}
is called immediately before a row
is updated due to an edit and receives the ORM row object to be changed
and a reference to the hash of form values (again with submit already
deleted).  You should make changes to the form hash, not to the object,
since the hash will be used to update the object.  This is good place
to specify modified times, etc.

Finally, \verb+delete_pre_action+\index{delete pre
action@\verb+delete_pre_action+}
is called after the user has confirmed
that a row should be deleted from the table.  This method, is called with
the doomed row object courtesy of the ORM.

If your pre hook does not like the change about to be made, it has no
choice but to use croak (or die).  That is the only way to stop the madness.
If you need a better bail out mechanism, you need to use real CRUD -- see
the next section.

Note that if all you need to do in your pre hooks is set false dates
to NULL, you don't need to bother, since AutoCRUD knows to do that.  All
you need to do is make sure the form fields have an \verb+is+ key and that
it is only boolean for actual booleans.  If you don't want that behavior
or have more date work to do, either implement a pre hook or use CRUD.

\subsection{Post Update Hooks}

Immediately after committing changes to the database, AutoCRUD attempts
to call a post hook.  These are named
\verb+add_post_action+,\index{add post action@\verb+add_post_action+}
\verb+edit_post_action+,\index{edit post action@\verb+edit_post_action+} and
\verb+delete_post_action+.\index{delete post action@\verb+delete_post_action+}

The add and edit post hooks are called with the newly created or freshly
modified row object.  Since the row is gone when it gets called, the delete
post hook is given the id of the deceased row.  These are good places to log
changes.

\subsection{Changing ORM Schemes}

By default, for historical reasons, AutoCRUD expects your ORM to
share the API of Class::DBI.  If your ORM has a different API, you
need to provide a bit of help to
AutoCRUD.\index{AutoCRUD!changing ORMs}

First, your base module should include a method like this:

{\footnotesize
\begin{verbatim}
sub get_orm_helper {
    return 'Gantry::Plugins::AutoCRUDHelper::SomeModule';
}
\end{verbatim}
}

If you use bigtop and DBIx::Class, you can set \verb+dbix+ to true on
the Control
Gantry backend.  Then the backend will create this method for
you.\begin{footnote}but it
goes into the stub, so it will only be made if \verb+dbix+ is set before
initial generation\end{footnote}
If you use some different ORM, you need to follow
the instructions below.

First, you need to create an ORM helper module.  Place it in the
{\footnotesize
\begin{verbatim}
Gantry::Plugins::AutoCRUDHelper
\end{verbatim}
}
\noindent
namespace.\index{AutoCRUD!ORM helpers}
This is not required,
but it is consistent with other helper naming.
For example, if you use DBIx::Class -- as we now do -- your
\verb+get_orm_helper+ should return:
{\footnotesize
\begin{verbatim}
Gantry::Plugins::AutoCRUDHelper::DBIxClass
\end{verbatim}
}
\noindent
If there is not already
a helper for your ORM, don't worry.  They are easy to write.

Each AutoCRUDHelper must implement four class methods:
{\footnotesize
\begin{verbatim}
insert
retrieve
update
delete
\end{verbatim}
}
\noindent
Remember that these
are class methods, so their
first argument is always the invoking class.

All of the methods below are passed the Gantry site object.  You probably
need to call \verb+get_model_name+ to find out your table name.  Depending
on how your models work, you may need to call another method on the result
(e.g. when using DBIx::Class you must call \verb+table_name+).

The \verb+insert+ method receives the Gantry site object and a
hash reference of
form parameters.  That hash is already sanitized and ready for immediate
insertion into the database.

The \verb+retrieve+ method receives the Gantry site object and the
single column primary key to retrieve.  

The \verb+update+ method receives the Gantry site object, the ORM row to be
changed (the row was generated by the retrieve method), and a hash reference
of form parameters sanitized and ready for immediate application to the
row.

Finally, the \verb+delete+ method is called with the Gantry site object and the
doomed row object (also obtained from the retrieve method).

Remember to trigger a database commit at the end of each of these helper
methods.  AutoCRUD is advertised as fully automatic, but it does not know
how to commit with your ORM.

There are currently two AutoCRUDHelpers, one for DBIx::Class and one for
Class::DBI.  Consult them for additional advice on implementing your own.

\section{CRUD}

The impetus for the creation of CRUD was AutoCRUD's inability to work on two
tables in the same controller.  But, once it came to be, we discovered that
the extra flexibility and transparency are quite nice, and we frequently use
it when AutoCRUD would also work.

For each possible CRUD cycle, you need to create a CRUD object.  During
construction, you fully describe how it should work.  This section explains
all the things you can put in that description and how
to drive the CRUD in your code.  For a single simple
example of CRUD use see the Job controller in Chapter \ref{chap:jobadsapp},
which uses it to link skills to job descriptions.

\subsection{Summary of CRUD Construction}

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Parameter Name & Meaning \\
\hline
\verb+add_action+      & Called when add data validates.              \\
\verb+edit_action+     & Called when edit data validates.             \\
\verb+delete_action+   & Called after confirmed deletion.             \\
\verb+form+            & Must return a form hash.                     \\
\verb+validator+       & Called to validate the form params.          \\
\verb+redirect+        & Called after successful submit               \\
                       & or cancel.                                   \\
\verb+template+        & Your form's template file name.              \\
                       & (a string)                                   \\
\verb+text_descr+      & Fills in the blank after `Delete ...?'       \\
\verb+turn_off_clean_params+
                       & Turns off setting all non-boolean            \\
                       & false fields to \verb+undef+ before          \\
                       & invoking \verb+add_action+ or                \\
                       & \verb+edit_action+.     \\
\verb+use_clean_dates+ & Sets all false date fields to \verb+undef+   \\
                       & before invoking \verb+add_action+ or         \\
                       & \verb+edit_action+.   \\
\end{tabular}
\end{center}
\caption{CRUD object constructor parameters.}
\label{tab:crudconstructor}
\end{table}

All the things you can pass as named parameters to the CRUD
constructor\index{CRUD!constructing object}
are shown in Table \ref{tab:crudconstructor}.
If you want to \verb+use_clean_dates+, you must
\verb+turn_off_clean_params+.
A simple constructor call might look like this:

{\footnotesize
\begin{verbatim}
my $special_crud = Gantry::Plugins::CRUD->new(
    add_action  => \&special_add,
    edit_action => \&special_edit,
    form        => \&special_form,
    text_descr  => 'item',
);
\end{verbatim}
}

Note that you must pass a list of pairs and not an actual hash reference.
\verb+template+\index{template!for form in
CRUD}\index{CRUD!form template}
and
\verb+text_description+\index{text
description@\verb+text_description+!CRUD}\index{CRUD!text description}
are just strings.
\verb+turn_off_clean_params+\index{turn off clean
params@\verb+turn_off_clean_params+}\index{CRUD!param cleanup}
and \verb+use_clean_dates+\index{CRUD!date cleanup}
are booleans.
The others are all callbacks.  The details of how, when, and with what those
callbacks are called follow below.

If you don't \verb+turn_off_clean_params+, it will walk through all
the fields in the param hash setting the false values to \verb+undef+, unless
they are booleans or ints.  If you do turn it off, you can turn on
\verb+use_clean_dates+, which does the same thing, but only for date fields.

Keep in mind that there is no rule that all CRUD objects must handle all
three CRUD activities.  If you want one that only adds or only edits, simply
omit the other actions from your constructor call and refrain from calling
them on the resulting object.  Note that the example above has no delete
action.  Perhaps in this case, deletes are not allowed.

If you need different forms for adding and editing, just use two CRUD objects.

\subsection{The Basics}

Let's start with the most common callbacks, leaving redirects for the next
subsection and remembering that forms were covered in the first section of
this chapter.

The processes don't begin with the callbacks, so we need to step back to the
user actions.  There are typically three of these:
\verb+do_add+,\index{do add@\verb+do_add+!CRUD}\index{CRUD!do methods}
\verb+do_edit+,\index{do edit@\verb+do_edit+!CRUD}
and/or
\verb+do_delete+,\index{do delete@\verb+do_delete+!CRUD}
but the names are up to you.  Further,
remember that there are frequently multiple sets of these in modules that
use CRUD.  So you might \verb+do_post_add+ and \verb+do_comment_add+, etc.
In all cases, you write those routines.\footnote{or let bigtop write them}
In them, you call
\verb+add+,\index{add@\verb+add+, CRUD callback}\index{CRUD!callbacks}
\verb+edit+,\index{edit@\verb+edit+, CRUD callback}
or
\verb+delete+\index{delete!CRUD callback}
on the CRUD object, when it accepts a form
submission, it calls you back.  Here's an example:

{\footnotesize
\begin{verbatim}
sub do_add {
    my ( $self, $parent_row_id ) = @_;

    $my_crud->add( $self, { parent_row => $parent_row_id } );
}
\end{verbatim}
}

The other actions (i.e. edit and delete) work similarly, just change the
method names.  Remember to put anything your form will need into the data
hash you pass to the CRUD \verb+add+, \verb+edit+, or \verb+delete+
methods.  For example, \verb+edit+ and \verb+delete+ need at least the
id of the row to act on, but they
might prefer to receive the row object.  There are examples below.

The data hash is also passed to the redirect callback.  I put the parent
row into the hash in the above example, so the redirect callback can go
to the proper page when the user cancels the operation.  It will also
be there for redirection when the user successfully submits the form.

%As I mentioned above, when implementing an edit handler, you should
%put the row to be edited into
%the data hash, so the form will know which row to use for initial default
%values.

Remember, the user's click actually triggers your \verb+do_*+ method.  In it,
do any prep work, then call the corresponding method on your CRUD object.
When the user successfully submits the form, CRUD will call you back.
For the above that callback\index{CRUD!callbacks!sample add action}
might look like this:

{\footnotesize
\begin{verbatim}
sub add_action {
    my ( $self, $params, $data ) = @_;

    $MYMODEL->gcreate( $self, $params );

    # ensure proper relocation
    if ( $params->{ parent_row } != $data->{ parent_row } ) {
        $data->{ parent_row } = $params->{ parent_row };
    }
}
\end{verbatim}
}

Here I've shown how to make a new row using Gantry's sugar method
\verb+gcreate+.\index{gcreate@\verb+gcreate+ ORM sugar
method}\index{ORM!sugar!gcreate@\verb+gcreate+}
Note that the add action updates the parent row, because the user had a
chance to change it on the form.  This row controls redirection.  Setting
it only in the action would not work, because cancellations don't flow through
the action.

There are many other things you could do in an action, including updating
several table based on the form input or sending mail to interested parties.
But, you could also use CRUD as a more transparent alternative to AutoCRUD.

The other work flows\index{CRUD!edit and delete} are similar:

{\footnotesize
\begin{verbatim}
sub do_edit {
    my ( $self, $row_id ) = @_;

    my $row    = $MYMODEL->gfind( $self, $row_id );

    $my_crud->edit( $self, { row => $row } );
}

sub edit_action {
    my ( $self, $params, $data ) = @_;

    $params->{ modified } = 'now';

    $data->{ row }->update( $params );
}

sub do_delete {
    my ( $self, $row_id, $yes ) = @_;

    my $row    = $MYMODEL->gfind( $self, $row_id );

    $my_crud->delete( $self, $yes, { row => $row } );
}

sub delete_action {
    my ( $self, $data ) = @_;

    $data->{ row }->delete;
}
\end{verbatim}
}

This \verb+edit_action+ assumes PostgreSQL.  See Section \ref{sec:faqdbnow}
in the Appendix or Section \ref{sec:jobadchangelog} for how to do the same
thing in MySQL and SQLite.

Note also that the delete method receives the doomed row id and the user's
confirmation flag, both of those must be forwarded on to the CRUD object's
delete method.

All of the above examples assume you have autocommit set on your
database handle.  If you aren't autocommitting, remember to begin
transactions and commit them.

\subsection{Controlling Redirection}

After the user either cancels or successfully submits a form, you want
to take them to an appropriate place.  By
default\index{CRUD!redirect locations}
that place will come from
calling \verb+location+ on the Gantry site object.  If you want users to
go somewhere else, you need to supply a code reference as the
\verb+redirect+\index{redirect CRUD constructor argument}
parameter to your CRUD constructor.

When your redirect callback is invoked, CRUD will pass it four things:
(1) your Gantry site object, (2) your data hash, (both of these you must
pass when calling \verb+add+, \verb+edit+, or \verb+delete+ on your CRUD
object), (3) the button action: cancel or submit, and (4) the CRUD
method: add, edit, or delete.  From these you decide where to go.
Once you decide, return a value URL in a
string\index{CRUD!redirection example}\index{redirect to main}:

{\footnotesize
\begin{verbatim}
sub redirect_to_main {
    my ( $self, $data, $button_action, $request ) = @_;

    if ( $data{ parent_id } ) {
        return $self->app_rootp
               . '/base/main/'
               . $data->{ parent_id };
    }
    elsif ( $data{ row } ) {
        return $self->app_rootp
               . '/base/main/'
               . $data->{ row }->parent_id;
    }
    else {
        return $self->location;
    }
}
\end{verbatim}
}

Note that if you return an undefined value, the
default\index{CRUD!default redirection location}
relocation will
be used.  That is, if the else block above had a bare return, the user would
go to \verb+$self->location+ anyway.

\subsection{Validation\index{form validation}}
\label{ssec:validate}

By default, form parameters are validated with
Data::FormValidator\index{Data::FormValidator!overriding with CRUD}
as
described earlier in this chapter and in various other places throughout
this book.  But, you can take over validation for yourself, if you use
CRUD.  First, supply a
\verb+validator+\index{validator!CRUD callback}\index{CRUD!validator callback}
callback to the CRUD constructor.
When it is time to check your user's integrity, err data integrity,
CRUD will call your method with the parameters in Table
\ref{tab:validatorparams}.  The parameters are named and come in
a single hash reference.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Parameter & Description \\
\hline
\verb+your_self+ & Your Gantry site object                   \\
\verb+params+    & A hash reference of form parameters       \\
\verb+form+      & The form hash from your form method       \\
\verb+profile+   & The profile of your form hash (see below) \\
\verb+action+    & Either `add' or `edit'                    \\
\end{tabular}
\end{center}
\caption{Parameters passed to validator CRUD callback.}
\label{tab:validatorparams}
\end{table}

Feel free to change the contents of \verb+params+ and \verb+form+ as
needed.  In particular, if you modify \verb+params+, those modifications
will be available in your action callback.
Or, as another example, giving the
\verb+error_text+\index{error text@\verb+error_text+}
\verb+form+
key a value will not only count as a validation failure, but will show
the value you supplied as an error message when the form is
redisplayed.\begin{footnote}
so long as your template honors \verb+error_text+ as the default
template does
\end{footnote}

The \verb+profile+\index{profile}\index{Gantry::Utils::CRUDHelp, profile}
is generated by Gantry::Utils::CRUDHelp and is a hash
with three keys that are shown in Table \ref{tab:formprofilekeys}.
You are under no obligation to use the profile.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Key & Meaning \\
\hline
\verb+required+           & An array (ref) of required field names   \\
\verb+optional+           & An array (ref) of optional field names   \\
\verb+constraint_methods+ & A hash (ref) keyed by field name         \\
                          & storing a Data::FormValidator            \\
                          & constraint                               \\
\end{tabular}
\end{center}
\caption{Keys in the profile hash passed the CRUD validator callbacks.}
\label{tab:formprofilekeys}
\end{table}

Do whatever you like in your validator callback, but return
an object with the
Data::FormValidator::Results\index{Data::FormValidator::Results API} API.
Normally, you get that object by calling \verb+new+ on
Gantry::Utils::FormErrors.  Pass a single hash reference with \verb+missing+
and \verb+invalid+ keys.  Both are optional; each must be a hash reference.
The keys in the hash are field names, values are true if the field is
missing or invalid.

Should you need to implement your own results class,
the methods actually called by the CRUD plugin and/or Gantry's
default form template are listed in Table \ref{tab:formvalidatorapi}.

\begin{table}
\begin{center}
\begin{tabular}{l|l}
Method & Returns \\
\hline
\verb+has_missing+ & true if there were missing required fields \\
\verb+has_invalid+ & true if there were invalid fields \\
\verb+missing+ & depends on how it is called see discussion \\
\verb+invalid+ & also depends on how it is called \\
\end{tabular}
\end{center}
\caption{Methods in Data::FormValidator::Results API.}
\label{tab:formvalidatorapi}
\end{table}

The \verb+missing+ and \verb+invalid+ methods return the number of
fields of their category when called without arguments.  If called with
an argument, that argument is the name of a field.  They must return true
if the field is in their category and false otherwise.

\section*{Summary}

That's about all there is to say about CRUD and AutoCRUD.  The only things
not covered here are the specifics of Data::FormValidator which has its
own fine manual.
